package com.ruoyi.assemble.fastloader.controller;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ZipUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.assemble.fastloader.model.*;
import com.ruoyi.assemble.fastloader.service.ChunkService;
import com.ruoyi.assemble.fastloader.service.FileInfoService;
import com.ruoyi.assemble.fastloader.util.FileInfoUtils;
import com.ruoyi.assemble.fastloader.util.ServletUtils;
import com.ruoyi.common.core.utils.file.FileTypeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 上传分片上传、文件下载、文件解压缩
 * @author yu-qh
 * 参考源码地址：https://gitee.com/luckytuan/fast-loader 原作者 @author 洋葱骑士
 *
 */
@RestController
@RequestMapping("/uploader")
public class FileController {

    @Value("${prop.upload-folder}")
    private String uploadFolder;

    @Value("${prop.parse-url}")
    private String parseUrl;

    @Value("${prop.parse-count}")
    private int parseCount;

    @Resource
    private FileInfoService fileInfoService;

    @Resource
    private ChunkService chunkService;

    private static String filePath = null;

    private final Logger logger = LoggerFactory.getLogger(FileController.class);

    /**
     * 分片上传文件块
     *
     * @param chunk
     * @return
     */
    @PostMapping("/chunk")
    public String uploadChunk(TChunkInfo chunk) {
        String apiRlt = "200";

        MultipartFile file = chunk.getUpfile();
        logger.info("file originName: {}, chunkNumber: {}", file.getOriginalFilename(), chunk.getChunkNumber());

        try {
            byte[] bytes = file.getBytes();
            Path path = Paths.get(FileInfoUtils.generatePath(uploadFolder, chunk));
            //文件写入指定路径
            Files.write(path, bytes);
            if (chunkService.saveChunk(chunk) < 0) {
                apiRlt = "415";
            }

        } catch (IOException e) {
            e.printStackTrace();
            apiRlt = "415";
        }
        return apiRlt;
    }

    /**
     * 断点续传
     * @param chunk
     * @param response
     * @return
     */
    @GetMapping("/chunk")
    public UploadResult checkChunk(TChunkInfo chunk, HttpServletResponse response) {
        UploadResult ur = new UploadResult();

        //默认返回其他状态码，前端不进去checkChunkUploadedByResponse函数，正常走标准上传
        response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);

        String file = uploadFolder + "/" + chunk.getIdentifier() + "/" + chunk.getFilename();

        //先判断整个文件是否已经上传过了，如果是，则告诉前端跳过上传，实现秒传
        if (FileInfoUtils.fileExists(file)) {
            ur.setSkipUpload(true);
            ur.setLocation(file);
            response.setStatus(HttpServletResponse.SC_OK);
            ur.setMessage("完整文件已存在，直接跳过上传，实现秒传");
            return ur;
        }

        //如果完整文件不存在，则去数据库判断当前哪些文件块已经上传过了，把结果告诉前端，跳过这些文件块的上传，实现断点续传
        ArrayList<Integer> list = chunkService.checkChunk(chunk);
        if (list != null && list.size() > 0) {
            ur.setSkipUpload(false);
            ur.setUploadedChunks(list);
            response.setStatus(HttpServletResponse.SC_OK);
            ur.setMessage("部分文件块已存在，继续上传剩余文件块，实现断点续传");
            return ur;
        }
        return ur;
    }

    public static final String THREE_ZERO_ZERO = "300";
    public static final String TWO_ZERO_ZERO = "200";
    public static final String ZIP = ".zip";

    /**
     * 拼接文件
     * @param fileInfoVO
     * @return
     */
    @PostMapping("/mergeFile")
    public HashMap mergeFile(@RequestBody TFileInfoVO fileInfoVO) {

        HashMap rlt = new HashMap();
        rlt.put("msg","FALURE");

        //前端组件参数转换为model对象
        TFileInfo fileInfo = new TFileInfo();
        fileInfo.setFilename(fileInfoVO.getName());
        fileInfo.setIdentifier(fileInfoVO.getUniqueIdentifier());
        fileInfo.setId(fileInfoVO.getId());
        fileInfo.setTotalSize(fileInfoVO.getSize());
        fileInfo.setRefProjectId(fileInfoVO.getRefProjectId());
        fileInfo.setType(FileTypeUtils.getFileType(fileInfo.getFilename()));

        //进行文件的合并操作
        String filename = fileInfo.getFilename();
        String file = uploadFolder + "/" + fileInfo.getIdentifier() + "/" + filename;
        String folder = uploadFolder + "/" + fileInfo.getIdentifier();
        String fileSuccess = FileInfoUtils.merge(file, folder, filename);

        fileInfo.setLocation(file);

        //文件合并成功后，保存记录至数据库
        if (TWO_ZERO_ZERO.equals(fileSuccess)) {
            String idTem = fileInfoService.addFileInfo(fileInfo);
            if ( idTem != null) {
                rlt.put("msg","SUCCESS");
                rlt.put("id",idTem);
                /*if(fileInfo.getFilename().endsWith(ZIP)){
                    boolean a = unZip(fileInfo);
                }*/
            }
        }

        //如果已经存在，则判断是否同一个项目，同一个项目的不用新增记录，否则新增
        if (THREE_ZERO_ZERO.equals(fileSuccess)) {
            List<TFileInfo> tfList = fileInfoService.selectFileByParams(fileInfo);
            if (tfList != null) {
                String pId1 = fileInfo.getRefProjectId();
                String pId2 = tfList.size() == 0 ? null : tfList.get(0).getRefProjectId();
                if (tfList.size() == 0 || !pId2.equals(pId1)) {
                    String idTem = fileInfoService.addFileInfo(fileInfo);
                    if ( idTem != null) {
                        rlt.put("msg","SUCCESS");
                        rlt.put("id",idTem);
                        /*if(fileInfo.getFilename().endsWith(ZIP)){
                            boolean a = unZip(fileInfo);
                        }*/
                    }
                } else {
                    //不用新增  状态删除1，需要改为0
                    if(tfList.size()>0){
                        fileInfo.setId(tfList.get(0).getId());
                        fileInfo.setDelFlag("0");
                        fileInfoService.deleteFile(fileInfo);
                    }
                    rlt.put("msg","SUCCESS");
                }
            }
        }

        return rlt;
    }

    /**
     * 查询列表
     *
     * @return ApiResult
     */
    @RequestMapping(value = "/selectFileList", method = RequestMethod.POST)
    public ApiResult selectFileList(@RequestBody QueryInfo query) {
        PageHelper.startPage(query.getPageIndex(), query.getPageSize());
        List<TFileInfo> list = fileInfoService.selectFileList(query);
        PageInfo<TFileInfo> pageResult = new PageInfo<>(list);
        return ApiResult.success(pageResult);
    }

    public static final int EIGHT_ONE_NINE_TWO = 8192;

    /**
     * 下载文件
     *
     * @param req
     * @param resp
     */
    @RequestMapping(value = "/download", method = RequestMethod.POST)
    public void download(HttpServletRequest req, HttpServletResponse resp) {
        String location = req.getParameter("location");
        String fileName = req.getParameter("filename");
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        OutputStream fos = null;
        try {
            bis = new BufferedInputStream(new FileInputStream(location));
            fos = resp.getOutputStream();
            bos = new BufferedOutputStream(fos);
            ServletUtils.setFileDownloadHeader(req, resp, fileName);
            int byteRead = 0;
            byte[] buffer = new byte[8192];
            while ((byteRead = bis.read(buffer, 0, EIGHT_ONE_NINE_TWO)) != -1) {
                bos.write(buffer, 0, byteRead);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bos.flush();
                bis.close();
                fos.close();
                bos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 删除
     */
    @RequestMapping(value = "/deleteFile", method = RequestMethod.POST)
    public ApiResult deleteFile(@RequestBody TFileInfo tFileInfo) {
        tFileInfo.setDelFlag("1");
        int result = fileInfoService.deleteFile(tFileInfo);
        return ApiResult.success(result);
    }

    /**
     * 解压Zip文件
     *
     * @param info 文件路径 String file = uploadFolder + "/" + fileInfo.getIdentifier() + "/" + filename;
     */
    public Boolean unZip(TFileInfo info) {
        try {
            ZipUtil.unzip(info.getLocation(),uploadFolder + "/" + info.getIdentifier(), Charset.forName("GBK"));
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
        //获取主文件目录 EGRID FEGRID
        //创建相应的解析结果目录
        File file = new File(uploadFolder + "/" + info.getIdentifier() + "/" + "parse");
        if(!file.exists()){
            new File(uploadFolder + "/" + info.getIdentifier()  + "/" + "parse/").mkdirs();
        }
        return true;
    }

    /*public static void getEgridLocation(String path) {
        //String path = "F:/测试目录"; // 路径
        File f = new File(path);
        if (!f.exists()) {
            System.out.println(path + "文件目录 not exists");
        }
        File[] fa = f.listFiles();
        //获取数组中的第i个
        assert fa != null;
        for (File fs : fa) {
            if (fs.isDirectory()) {
                System.out.println(fs.getName() + " [目录]");
                if (Objects.requireNonNull(fs.listFiles()).length > 0) {
                    System.out.println("目录:" + fs.getPath());
                    getEgridLocation(fs.getPath());
                }
            } else {
                String kzm = fs.getName().split("\\.")[fs.getName().split("\\.").length - 1];
                boolean r = !StringUtils.isEmpty(kzm) && (kzm.toUpperCase().endsWith("EGRID") || kzm.toUpperCase().endsWith("FEGRID"));
                if (r) {
                    filePath = fs.getAbsolutePath();
                    break;
                }
            }
        }
    }*/

    /*public static void getHttpCientAsync(String parseUrl , HashMap paramMap){
        System.out.println("异步调用:"+parseUrl);
        String result = HttpRequest.get(parseUrl)
                ////.header(Header.USER_AGENT, "Hutool http")//头信息，多个头信息多次调用此方法即可
                .form(paramMap)
                ////.timeout(20000)//超时，毫秒
                .execute().body();
        System.out.println("异步调用:执行完成:" + result);
    }*/


    /**
     * main
     *
     * @author 
     * @description main
     * @time 2022/8/31 15:51
     * @param args
     * @return void
     */
    public static void main(String args[]){
        //getSleep123();
        ThreadUtil.execAsync(()->getSleep123(),false);
    }
    public static void getSleep123(){
        try {
            Thread.sleep(1000*10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sleep");
    }
}
